﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Multithreading多线程
{
    /// <summary>
    /// Thread启动异步多线程
    ////直接传递方法，构造函数还是一个委托
    ///但是不能使用Action ，Func 因为当时使用Thread还是1.0的时候没有Action ，Func
    ///所以使用的是ParameterizedThreadStart 带参数委托
    ///ThreadStart 不带参数的委托
    /// </summary>
    public class MyThreadDoem
    {
        /// <summary>
        /// 使用Thread 创建多线程
        /// </summary>
        public static void Show()
        {
            //实例化创建线程 无参无返回值
            Thread thread = new Thread(() =>
            {
                Console.WriteLine("我是多线程");
            });
            thread.Start();

            //创建5个线程1
            for (int i = 0; i < 5; i++)
            {
                //这个之所以创建一个k，后面线程不安全会说到
                var k = i;
                //这是一个有参数无返回值多线程,但是参数是一个不安全的参数
                new Thread(x => Running(Convert.ToInt32(x))).Start(k);
            }
            Console.Read();
        }

        /// <summary>
        /// 使用Thread 线程挂起、唤醒线程、销毁，方式是抛异常、取消Abort异常
        /// </summary>
        public static void Show1()
        {
            //创建一个Thread 线程
            Thread thread = new Thread(() =>
            {
                Running();
            });
            //开启线程
            thread.Start();
            //这个是线程挂起
            //thread.Suspend();
            //唤醒线程
            //thread.Resume();
            //上面的两个方法，现在已经弃用了，因为我们无法精确地控制线程的开启与暂停
            //当我们将线程挂起的时候，同时也会挂起线程使用的资源，会导致死锁，不建议使用
            try
            {
                //将线程销毁
                //也不建议    不一定及时/有些动作发出收不回来
                thread.Abort();
            }
            catch (Exception)
            {
                //静态方法将线程异常取消继续工作
                Thread.ResetAbort();
            }
            Console.Read();
        }

        /// <summary>
        /// 使用Thread 线程等待
        /// </summary>
        public static void Show2()
        {
            //创建一个Thread 线程
            Thread thread = new Thread(() =>
            {
                Running();
            });
            //开启线程
            thread.Start();
            //堵塞线程等待执行完后
            //thread.Join();
            //堵塞线程 等待执行完后
            //thread.Join(-1);
            //堵塞线程 最多等待1秒钟
            //thread.Join(1000);

            //thread.ThreadState 是当前线程的状态枚举 有16种
            // ThreadState.Stopped 是线程成功执行完了
            while (thread.ThreadState != ThreadState.Stopped)
            {
                Thread.Sleep(100);//当前线程 休息100ms  
            }
            Console.WriteLine("执行完啦啦啦啦啦啦啦啦啦啦啦拉拉");
            Console.Read();
        }

        /// <summary>
        /// 使用Thread 线程的优先级（但是执行还是看CPU，可以做优先级，但是不是绝对优先）
        /// </summary>
        public static void Show3()
        {
            //创建一个Thread 线程
            Thread thread = new Thread(() =>
            {
                Running();
            });
            thread.Start();
            //thread.Priority属性可以设置线程的优先级关系
            thread.Priority = ThreadPriority.Highest;
            Console.WriteLine("执行完啦啦啦啦啦啦啦啦啦啦啦拉拉");
            Console.Read();
        }

        /// <summary>
        /// 使用Thread 前台线程，后台线程
        ///默认是前台线程，启动之后一定要完成任务的，阻止进程退出
        ///指定后台线程：随着进程退出
        /// </summary>
        public static void Show4()
        {
            //创建一个Thread 线程
            Thread thread = new Thread(() =>
            {
                Running();
            });
            //默认是前台线程，启动之后一定要完成任务的，阻止进程退出
            //指定后台线程：随着进程退出
            thread.IsBackground = true;
            Console.WriteLine("执行完啦啦啦啦啦啦啦啦啦啦啦拉拉");
            Console.Read();
        }
        
        /// <summary>
        /// 防止参数不安全
        /// </summary>
        public static void Show5()
        {
            //我们创建一个泛型类，限制我们的类型
            MyThread<string> mythread = new MyThread<string>("Thread_child");
            //将我们的方法传递,进去
            Thread th3 = new Thread(mythread.ThreadChild);
            //启动线程
            th3.Start();
        }

        /// <summary>
        /// 创建一个泛型类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        class MyThread<T>
        {
            private T data;
            public MyThread(T data)
            {
                this.data = data;
            }
            public void ThreadChild()
            {
                Console.WriteLine("Child Thread Start! Result:{0}", data);
            }
        }

        /// <summary>
        /// 异步回调执行
        /// </summary>
        public static void Show6() {
            //创建一个任务委托
            ThreadStart threadStart = () => {
                Console.WriteLine("我是任务");
            };
            //创建一个回调执行的委托
            Action action = () => {
                Console.WriteLine("哈哈，我就是你们的回调方法哈，记得双击么么哒");
                Console.WriteLine("*********************************************");
            };
            ThreadWithCallback(threadStart, action);
            Console.ReadLine();
        }

        /// <summary>
        /// 异步返回值
        /// </summary>
        public static void Show7()
        {
            //创建一个委托
            Func<string> func = () => {
                return "我是返回值";
            };
            //获取执行结果
            Console.WriteLine(ThreadWithReturn(func).Invoke());
            Console.ReadLine();
        }

        #region 回调封装
        /// <summary>
        /// 回调封装 无返回值
        /// </summary>
        /// <param name="start"></param>
        /// <param name="callback">回调</param>
        private static void ThreadWithCallback(ThreadStart start, Action callback)
        {
            Thread thread = new Thread(() =>
            {
                start.Invoke();
                callback.Invoke();
            });
            thread.Start();
        }

        /// <summary>
        /// 有返回值封装（请根据本案例自行封装回调）
        /// </summary>
        /// <typeparam name="T">返回值类型</typeparam>
        /// <param name="func">需要子线程执行的方法</param>
        /// <returns></returns>
        private static Func<T> ThreadWithReturn<T>(Func<T> func)
        {
            //初始化一个泛型，限制我们的类型
            T t = default(T);
            ThreadStart newStart = () =>
            {
                //线程给变量赋值
                t = func.Invoke();
            };
            //创建线程
            Thread thread = new Thread(newStart);
            //执行线程
            thread.Start();
            //创建一个委托 无参有返回值，执行委托会发生执行线程等待堵塞
            //当线程执行完之后，也就是说线程已经给变量t赋值了，我们就返回t
            return new Func<T>(() =>
            {
                thread.Join();
                return t;
            });
        }
        #endregion

        /// <summary>
        /// 一个执行需要长时间的任务
        /// </summary>
        static void Running(int s)
        {
            Console.WriteLine("**********************************");
            Console.WriteLine("执行开始啦" + s);
            Console.WriteLine("获取当前执行的线程ID：" + Thread.CurrentThread.ManagedThreadId.ToString());
            var j = 0;
            for (int i = 0; i < 1000000000; i++)
            {
                j++;
            }
            Console.WriteLine("执行结束啦" + s);
        }

        /// <summary>
        /// 一个执行需要长时间的任务
        /// </summary>
        static int Running()
        {
            Console.WriteLine("**********************************");
            Console.WriteLine("执行开始啦");
            Console.WriteLine("获取当前执行的线程ID：" + Thread.CurrentThread.ManagedThreadId.ToString());
            var j = 0;
            for (int i = 0; i < 1000000000; i++)
            {
                j++;
            }
            Console.WriteLine("执行结束啦");
            return j;
        }
    }
}
